
package cn.tang.tframe.sdm.web.shiro.session;

import cn.tang.tframe.springredis.QtProjectRedisClient;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 此Session的过期时间可以来源于配置文件
 * 
 * @author tanghc
 */
@Component
@Scope("prototype")
public class AppRedisSessionDAO extends AbstractSessionDAO {

	private static Logger logger =
		LoggerFactory.getLogger(AppRedisSessionDAO.class);
	/**
	 * shiro-redis的session对象前缀
	 */
	/**
	 * The Redis key prefix for the sessions
	 */
	private String keyPrefix = "shiro_redis_session:";
	// private long expireSec = -1;
	private long expireMs = -1;

	@Override
	public void update(Session session)
		throws UnknownSessionException {

		if (session == null || session.getId() == null) {
			logger.error("session or session id is null");
			return;
		}
		Session sessionCache = getSessionCache((String) session.getId());
		if ((null != sessionCache && sessionCache.getTimeout() <= 0) ||
			session.getTimeout() <= 0) {
			logger.debug(
				"update session updateLoginTimeoutMs : session={}", session);
			updateLoginTimeoutMs((String) session.getId(), -1);
			saveSession(session, -1);
		}
		else {
			saveSession(session);
		}
	}

	private Session getSessionCache(String sessionId) {

		String key = getKey(sessionId);
		return (Session) QtProjectRedisClient.getSpringRedisCache().get(key);
	}

	public void updateLoginTimeoutMs(String sessionId, long loginTimeoutMs)
		throws UnknownSessionException {

		if (sessionId == null) {
			logger.error("session or session id is null");
			return;
		}
		String key = getKey(sessionId);
		AppSession session =
			(AppSession) QtProjectRedisClient.getSpringRedisCache().get(key);
		if (session != null) {
			if (loginTimeoutMs <= 0) {
				session.setTimeout(-1);
				QtProjectRedisClient.getSpringRedisCache().set(key, session);
				return;
			}
			else {
				updateSession(sessionId,loginTimeoutMs);
			}
		}
	}

	public void updateSession(String sessionId)
		throws UnknownSessionException {

		if (sessionId == null) {
			logger.error("session or session id is null");
			return;
		}
		String key = getKey(sessionId);
		saveSession(
			(Session) QtProjectRedisClient.getSpringRedisCache().get(key));
	}
	public void updateSession(String sessionId, long cusExpireMs)
		throws UnknownSessionException {

		if (sessionId == null) {
			logger.error("session or session id is null");
			return;
		}
		String key = getKey(sessionId);
		saveSession(
			(Session) QtProjectRedisClient.getSpringRedisCache().get(key),cusExpireMs);
	}

	protected byte[] getByteKey(Serializable sessionId) {

		String preKey = this.getKeyPrefix() + sessionId;
		return preKey.getBytes();
	}

	protected String getKey(Serializable sessionId) {

		String preKey = this.getKeyPrefix() + sessionId;
		return preKey;
	}

	/**
	 * save session
	 * 
	 * @param session
	 * @throws UnknownSessionException
	 */
	private void saveSession(Session session)
		throws UnknownSessionException {

		saveSession(session, expireMs);
	}

	private void saveSession(Session session, long cusExpireMs)
		throws UnknownSessionException {

		if (session == null || session.getId() == null) {
			logger.error("session or session id is null");
			return;
		}
		if (session instanceof AppSession) {
			String key = getKey(session.getId());
			if (cusExpireMs <= 0) {
				session.setTimeout(-1);
				QtProjectRedisClient.getSpringRedisCache().set(
					key, (AppSession) session);
				return;
			}
			else {
				session.setTimeout(cusExpireMs);
				QtProjectRedisClient.getSpringRedisCache().set(
					key, (AppSession) session, cusExpireMs,
					TimeUnit.MILLISECONDS);
				return;
			}
		}
	}

	@Override
	public void delete(Session session) {

		if (session == null || session.getId() == null) {
			logger.error("session or session id is null");
			return;
		}
		QtProjectRedisClient.getSpringRedisCache().del(
			this.getKey(session.getId()));

	}

	@Override
	public Collection<Session> getActiveSessions() {

		Set<Session> sessions = new HashSet<Session>();
		Set<String> keys = QtProjectRedisClient.getSpringRedisCache().keys(
			this.getKeyPrefix() + "*");
		if (keys != null && keys.size() > 0) {
			for (String key : keys) {
				Session s =
					(Session) QtProjectRedisClient.getSpringRedisCache().get(
						key);
				sessions.add(s);
			}
		}
		return sessions;
	}

	@Override
	protected Serializable doCreate(Session session) {

		Serializable sessionId = this.generateSessionId(session);
		this.assignSessionId(session, sessionId);
		this.saveSession(session);
		return sessionId;
	}

	@Override
	protected Session doReadSession(Serializable sessionId) {

		if (sessionId == null) {
			logger.error("session id is null");
			return null;
		}

		Session s = (Session) QtProjectRedisClient.getSpringRedisCache().get(
			this.getKey(sessionId));
		return s;
	}

	/**
	 * Returns the Redis session keys prefix.
	 * 
	 * @return The prefix
	 */
	public String getKeyPrefix() {

		return keyPrefix;
	}

	/**
	 * Sets the Redis sessions key prefix.
	 * 
	 * @param keyPrefix
	 *            The prefix
	 */
	public void setKeyPrefix(String keyPrefix) {

		this.keyPrefix = keyPrefix;
	}

	// public long getExpireSec() {
	// return expireSec;
	// }
	//
	// public void setExpireSec(long expireSec) {
	// this.expireSec = expireSec;
	// }
	public long getExpireMs() {

		return expireMs;
	}

	public void setExpireMs(long expireMs) {

		this.expireMs = expireMs;
	}
}
